home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / glass / glass.lha / GLASS / tm / tmlex.c < prev    next >
C/C++ Source or Header  |  1990-11-06  |  10KB  |  406 lines

  1. /* 
  2.    Copyright (C) 1990 C van Reewijk, email: dutentb.uucp!reeuwijk
  3.  
  4. This file is part of GLASS.
  5.  
  6. GLASS is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GLASS is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GLASS; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /* File: tmlex.c
  21.    Lexical analyzer for Miranda algebraic datatypes plus additions
  22.    for naming of constructor elements.
  23.  */
  24.  
  25. #include "tmdefs.h"
  26. #include <ctype.h>
  27. #include <tmc.h>
  28.  
  29. #include "tmds.h"
  30. #include "tmstring.h"
  31. #include "debug.h"
  32. #include "tmerror.h"
  33. #include "tmgram.h"
  34. #include "tmglobal.h"
  35. #include "tmlex.h"
  36. #include "tmmisc.h"
  37.  
  38. extern YYSTYPE yylval;
  39. extern double atof();
  40.  
  41. #ifdef DEBUG
  42. #define lexshow(tok,nm) if(lextr) fprintf(tracestream,"token: %s(%d). yytext=\"%s\".\n",nm,tok,yytext)
  43. #else
  44. #define lexshow(tok,nm)
  45. #endif
  46.  
  47. static char yytext[256];
  48.  
  49. /******************************************************
  50.  *                                                    *
  51.  *            SCANNING TREES                          *
  52.  *                                                    *
  53.  ******************************************************/
  54.  
  55. /* Scanning trees are used to recogize separator tokens.
  56.    They form a linked list of possible acceptable characters.
  57.    Each node may have a sub-list of possible extensions
  58.    and an the token value for the current match.
  59.  */
  60.  
  61. struct sctnode {
  62.     struct sctnode *next;   /* next possibility in list */
  63.     int sctchar;            /* char to match            */
  64.     struct sctnode *sub;    /* subtree to use on match. */
  65.     bool valid;             /* is acceptable token?     */
  66.     int tokval;             /* token value for yacc     */
  67.     char *toknm;            /* token name for debugging */
  68. };
  69.  
  70. #define SCTNIL (struct sctnode *)0
  71.  
  72. static long newsctnodecnt;
  73. static long fresctnodecnt;
  74.  
  75. struct sctnode *toktree;
  76.  
  77. /* Create a new scan tree node to match character 'c'. The next character
  78.    to be considered is described by node 'nxt'. The subtree is set empty,
  79.    and token is set invalid.
  80.  */
  81. static struct sctnode *newsctnode( nxt, c )
  82.  struct sctnode *nxt;
  83.  int c;
  84. {
  85.     struct sctnode *new;
  86.  
  87.     new = (struct sctnode *) ckmalloc( sizeof( struct sctnode ) );
  88.     newsctnodecnt++;
  89.     new->next    = nxt;
  90.     new->sctchar = c;
  91.     new->sub     = SCTNIL;
  92.     new->valid   = FALSE;
  93.     return( new );
  94. }
  95.  
  96. /* Recursively free scan tree node 'n'. */
  97. static void rfre_sctnode( n )
  98.  struct sctnode *n;
  99. {
  100.     if( n == SCTNIL ) return;
  101.     rfre_sctnode( n->next );
  102.     rfre_sctnode( n->sub );
  103.     free( (char *) n );
  104.     fresctnodecnt++;
  105. }
  106.  
  107. /* Add to the scan tree 'tree' a new token with string 'str',
  108.    YACC value 'val' and (debugging) name 'nm'.
  109.    Return a pointer to the modified tree.
  110.  */
  111. static struct sctnode *addtok( tree, str, val, nm )
  112.  struct sctnode *tree;
  113.  char *str;
  114.  int val;
  115.  char *nm;
  116. {
  117.     register struct sctnode *tp;
  118.  
  119.     for( tp=tree; tp!=SCTNIL; tp=tp->next ){
  120.     if( tp->sctchar == str[0] ) break;
  121.     }
  122.     if( tp == SCTNIL ){
  123.     tree = newsctnode( tree, str[0] );
  124.     tp = tree;
  125.     }
  126.     if( str[1] == '\0' ){
  127.     tp->valid = TRUE;
  128.     tp->tokval= val;
  129.     tp->toknm = nm;
  130.     }
  131.     else{
  132.     tp->sub = addtok( tp->sub, &str[1], val, nm );
  133.     }
  134.     return( tree );
  135. }
  136.  
  137. /******************************************************
  138.  *                                                    *
  139.  *            TOKEN AND RESERVED WORD TABLES          *
  140.  *                                                    *
  141.  ******************************************************/
  142.  
  143. /* A structure to describe tokens and reserved words */
  144. struct tok {
  145.     char *tokstr;   /* the string to match. */
  146.     int tokval;     /* associated token value for yacc */
  147.     char *toknm;    /* name for debugging */
  148. };
  149.  
  150. #define TOKNIL (struct tok *) 0;
  151.  
  152.  
  153. /* A table of tokens. Is terminated by an entry with empty string. */
  154. struct tok toktab[] =
  155. {
  156.     { "(", LRBRAC, "LRBRAC" },
  157.     { ")", RRBRAC, "RRBRAC" },
  158.     { ",", COMMA, "COMMA" },
  159.     { ":", COLON, "COLON" },
  160.     { "::=", COLCOLEQ, "COLCOLEQ" },
  161.     { ";", SEMI, "SEMI" },
  162.     { "==", EQEQ, "EQEQ" },
  163.     { "[", LSBRAC, "LSBRAC" },
  164.     { "]", RSBRAC, "RSBRAC" },
  165.     { "|", BAR, "BAR" },
  166.     { NULL, 0, "" }
  167. };
  168.  
  169. /* A table of reserved words: symbols that have a special meaning.
  170.    Is terminated by an entry with NULL string.
  171.  */
  172.  
  173. struct tok rwtab[] =
  174. {
  175.     { NULL, 0, "" }
  176. };
  177.  
  178. /******************************************************
  179.  *                                                    *
  180.  *            FILE MANAGEMENT                         *
  181.  *                                                    *
  182.  ******************************************************/
  183.  
  184. #define UNGETBUFLENSTEP 10
  185.  
  186. /* file to read from */
  187. FILE *lexfile;
  188.  
  189. /* variables for a dynamic unget buffer:
  190.    length, pointer to buffer and index of next char to un-get.
  191.  */
  192. static int ungetbuflen;
  193. static int *ungetbuf;
  194. static unsigned int ungetbufix;
  195.  
  196. /* push back character 'c' in local pushback queue.
  197.    Enlarge queue if necessary.
  198.  */
  199. static void lexungetc( c )
  200.  int c;
  201. {
  202.     if( ungetbufix >= ungetbuflen ){
  203.     ungetbuflen+=UNGETBUFLENSTEP;
  204.     ungetbuf = (int *) ckrealloc( (char *) ungetbuf, (unsigned) ungetbuflen*sizeof(int) );
  205.     }
  206.     ungetbuf[ungetbufix++] = c;
  207. }
  208.  
  209. /* Get a character from input stream or pushback queue. */
  210. static int lexgetc()
  211. {
  212.     register int c;
  213.  
  214.     if( ungetbufix != 0 ){
  215.     c = ungetbuf[--ungetbufix];
  216.     }
  217.     else {
  218.     c = getc( lexfile );
  219.     }
  220.     return( c );
  221. }
  222.  
  223. /* Try to read characters from 'lexgetc()' to match one of the tokens from the
  224.    table 'toktab' in the string 'buf'. The token characters to match are given 
  225.    by the scan tree 'tree'.
  226.    Fill '*tokval' with the token value, and '*toknm' with the name
  227.    of the token. Return TRUE if this is successful, else return FALSE.
  228.  */
  229. static bool scantoken( tree, buf, tokval, toknm )
  230.  struct sctnode *tree;
  231.  register char *buf;
  232.  int *tokval;
  233.  char **toknm;
  234. {
  235.     register int c;
  236.     register struct sctnode *tp;
  237.  
  238.     c = lexgetc();
  239.     if( c == EOF ) return( FALSE );
  240.     for( tp=tree; tp!=SCTNIL; tp=tp->next ){
  241.     if( tp->sctchar == c ) break;
  242.     }
  243.     if( tp == SCTNIL ){
  244.     lexungetc( c );
  245.     return( FALSE );
  246.     }
  247.     buf[0] = c;
  248.     if( scantoken( tp->sub, &buf[1], tokval, toknm ) ){
  249.     return( TRUE );
  250.     }
  251.     if( tp->valid ){
  252.     *tokval = tp->tokval;
  253.     *toknm = tp->toknm;
  254.     buf[1] = '\0';
  255.     return( TRUE );
  256.     }
  257.     lexungetc( c );
  258.     return( FALSE );
  259. }
  260.  
  261. /* Try to read a symbol in the string 'buf' using lexgetc(). Return TRUE if
  262.    this is successful, else return FALSE.
  263.    A symbol is of the form [a-zA-Z][a-zA-Z0-9_]*.
  264.  */
  265. static bool scansymbol( buf )
  266.  register char *buf;
  267. {
  268.     register int c;
  269.  
  270.     c = lexgetc();
  271.     if( !isalpha( c ) ){
  272.     lexungetc( c );
  273.     return( FALSE );
  274.     }
  275.     do{
  276.     *buf++ = c;
  277.     c = lexgetc();
  278.     } while( isalnum( c ) || c == '_' );
  279.     *buf = '\0';
  280.     lexungetc( c );
  281.     return( TRUE );
  282. }
  283.  
  284. /* "||" encountered, skip characters until end of line. */
  285. static void skipcomment()
  286. {
  287.     register int c;
  288.  
  289.     c = lexgetc();
  290.     while( c != '\n' ){
  291.     if( c == EOF ){
  292.         error( UNEXPECTEOF );
  293.         exit( 1 );
  294.     }
  295.     c = lexgetc();
  296.     }
  297.     dslineno++;
  298. }
  299.  
  300. /* Return next token from lex input file. Set 'yytext' to the characters
  301.  * of the next token, and 'yylval' to the associated value of the token.
  302.  */
  303. int yylex()
  304. {
  305.     register int c;
  306.     char *toknm;
  307.     int tokval;
  308.  
  309. again:
  310.     c = lexgetc();
  311.     if( c == '|' ){
  312.     c = lexgetc();
  313.     if( c == '|' ){
  314.         skipcomment();
  315.         goto again;
  316.     }
  317.     lexungetc( c );
  318.     c = '|';
  319.     }
  320.     if( c == '\n' ){
  321.     dslineno++;
  322.     goto again;
  323.     }
  324.     if( isspace( c ) ) goto again;
  325.     if( c == EOF ){
  326.     yytext[0] = '\0';
  327.     lexshow(EOF,"EOF");
  328.     return EOF;
  329.     }
  330.     lexungetc( c );
  331.     if( scansymbol( yytext ) ){
  332.     struct tok *rwp;
  333.  
  334.     for( rwp = rwtab; rwp->tokstr != NULL; rwp++ ){
  335.         if( strcmp( rwp->tokstr, yytext ) == 0 ){
  336.         lexshow(rwp->tokval,rwp->toknm);
  337.         return( rwp->tokval );
  338.         }
  339.     }
  340.     yylval.parstring = new_string( yytext );
  341.     lexshow(NAME,"NAME");
  342.     return NAME;
  343.     }
  344.     if( scantoken( toktree, yytext, &tokval, &toknm ) ){
  345.     lexshow(tokval,toknm);
  346.     return tokval;
  347.     }
  348.     c = lexgetc();
  349.     if( c >= ' ' && c<= 0x7e ){
  350.     (void) sprintf( errarg, "'%c'", c );
  351.     }
  352.     else {
  353.     (void) sprintf( errarg, "0x%02x", c );
  354.     }
  355.     (void) sprintf( errpos, "%s(%d)", dsfilename, dslineno );
  356.     error( BADTOK );
  357.     exit( 1 );
  358.     return( c );
  359. }
  360.  
  361. /* Initialize lexical analysis routines. */
  362. void init_lex()
  363. {
  364.     struct tok *ttp;
  365.  
  366.     newsctnodecnt=0;
  367.     fresctnodecnt=0;
  368.     ungetbuflen = 2;    /* Don't make this 0, some mallocs don't like it */
  369.     ungetbuf = (int *) ckmalloc( (unsigned) ungetbuflen*sizeof(int) );
  370.     ungetbufix = 0;
  371.     toktree = SCTNIL;
  372.     for( ttp = toktab; ttp->tokstr != NULL; ttp++ ){
  373.     toktree = addtok( toktree, ttp->tokstr, ttp->tokval, ttp->toknm );
  374.     }
  375. }
  376.  
  377. /* Terminate lexcial analysis routines. Free all allocated memory */
  378. void end_lex()
  379. {
  380.     rfre_sctnode( toktree );
  381.     toktree = SCTNIL;
  382.     free( (char *) ungetbuf );
  383.     ungetbuflen = 0;
  384.     ungetbufix = 0;
  385. }
  386.  
  387. /* Indicate that lex routines should read from file 'f'. */
  388. void setlexfile( f )
  389.  FILE *f;
  390. {
  391.     lexfile = f;
  392.     dslineno=1;
  393. }
  394.  
  395. /* Give allocation statistics of lex routines. */
  396. void stat_lex( f )
  397.  FILE *f;
  398. {
  399. #ifdef STAT
  400.     fprintf( f, "ungetbuflen=%d\n", ungetbuflen );
  401.     PRSTAT( f, "sctnode", newsctnodecnt, fresctnodecnt );
  402. #else
  403.     f = f; /* to stop 'f unused' */
  404. #endif
  405. }
  406.